// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package ssa

import (
	"cmd/internal/src"
	"fmt"
)

// 块表示函数控制流图中的基本块。
type Block struct {
	// 块的唯一标识符。系统将尝试分配
	// 这些ID很密集，但没有保证。
	ID ID

	// 块控制操作的源位置
	Pos src.XPos

	// 这是一种积木。
	Kind BlockKind

	// 分支的可能方向。
	// 如果是分支，则Succs[0]是最有可能执行的分支。
	// 如果可能，Succs[1]是最有可能执行的分支。
	// 如果len（Succs）<2，则忽略。
	// 如果未知和len（成功）>2，则致命。
	Likely BranchPrediction

	// flagalloc之后，记录块末尾的标志是否处于活动状态。
	FlagsLiveAtEnd bool

	// 后续块（如果有）。数量和顺序取决于块类型。
	Succs []Edge

	// 继承人的倒数。
	// 该顺序对于块中的Phi节点非常重要。
	// TODO:前辈是一种难以维持的痛苦。我们能不能点一份phi
	// 按块id设置参数，并在需要时显式计算此字段？
	Preds []Edge

	// 确定块如何退出的值列表。号码
	// 控制值的类型取决于块的类型。对于
	// 例如，BlockIf具有单个布尔控制值和BlockExit
	// 具有单个内存控制值。
	// None
	// ControlValues（）方法可用于获取非nil的切片
	// 控制可以设置范围的值。
	// None
	// 如果控件[0]为零，则控件[1]必须为零。
	Controls [2]*Value

	// 块的辅助信息。它的价值取决于种类。
	Aux    Aux
	AuxInt int64

	// 定义此块操作的无序值集。
	// 调度通过后，此列表将被排序。
	Values []*Value

	// 包含函数
	Func *Func

	// 成功、预测和价值的存储。
	succstorage [2]Edge
	predstorage [4]Edge
	valstorage  [9]*Value
}

// 边表示CFG边。
// b分支到c或d的边示例。
// （c和d还有其他前辈。）
// b、 Succs=[{c，3}，{d，1}]
// c、 Preds=[？，？，？，{b，0}]
// d、 Preds=[？，{b，1}，，]
// 这些索引允许我们在固定时间内编辑CFG。
// 此外，它在退化情况下通知phi ops，如：
// b:
// 如果是k，那么是c，否则是c
// c:
// v=φ（x，y）
// 然后索引告诉您是否从中选择了x
// 来自b的if或else分支。
// b、 Succs=[{c，0}，{c，1}]
// c、 Preds=[{b，0}，{b，1}]
// 如果k为真，则表示选择x。
type Edge struct {
	// 块边转到（在成功列表中）或从（在Preds列表中）
	b *Block
	// 反向边索引。不变量：
	// e:=x.Succs[idx]
	// e、 b.Preds[e.i]=边{x，idx}
	// 前辈也是如此。
	i int
}

func (e Edge) Block() *Block {
	return e.b
}
func (e Edge) Index() int {
	return e.i
}
func (e Edge) String() string {
	return fmt.Sprintf("{%v,%d}", e.b, e.i)
}

// 种类控制继承人
// ------------------------------------------
// 退出[返回内存][]
// 普通[][下一步]
// 如果[boolean Value][then，else]
// Defer[mem][nopanic，panic]（控制操作码应该是OpStaticCall to runtime.deferproc）
type BlockKind int8

// 简式印刷
func (b *Block) String() string {
	return fmt.Sprintf("b%d", b.ID)
}

// 长格式打印
func (b *Block) LongString() string {
	s := b.Kind.String()
	if b.Aux != nil {
		s += fmt.Sprintf(" {%s}", b.Aux)
	}
	if t := b.AuxIntString(); t != "" {
		s += fmt.Sprintf(" [%s]", t)
	}
	for _, c := range b.ControlValues() {
		s += fmt.Sprintf(" %s", c)
	}
	if len(b.Succs) > 0 {
		s += " ->"
		for _, c := range b.Succs {
			s += " " + c.b.String()
		}
	}
	switch b.Likely {
	case BranchUnlikely:
		s += " (unlikely)"
	case BranchLikely:
		s += " (likely)"
	}
	return s
}

// NumControls返回
// 布洛克有。
func (b *Block) NumControls() int {
	if b.Controls[0] == nil {
		return 0
	}
	if b.Controls[1] == nil {
		return 1
	}
	return 2
}

// ControlValues返回包含非nil控件的切片
// 块的值。每个控制值的索引将是
// 与控件属性中的相同，可以使用
// 在ReplaceControl调用中。
func (b *Block) ControlValues() []*Value {
	if b.Controls[0] == nil {
		return b.Controls[:0]
	}
	if b.Controls[1] == nil {
		return b.Controls[:1]
	}
	return b.Controls[:2]
}

// SetControl删除所有现有控件值，然后添加
// 提供的控制值。之后的控件值数
// 对SetControl的调用将始终为1。
func (b *Block) SetControl(v *Value) {
	b.ResetControls()
	b.Controls[0] = v
	v.Uses++
}

// ResetControls将块的控件数设置为0。
func (b *Block) ResetControls() {
	if b.Controls[0] != nil {
		b.Controls[0].Uses--
	}
	if b.Controls[1] != nil {
		b.Controls[1].Uses--
	}
	b.Controls = [2]*Value{} // 将两个控件重置为零
}

// AddControl将控件值附加到现有控件值列表中。
func (b *Block) AddControl(v *Value) {
	i := b.NumControls()
	b.Controls[i] = v // 如果数组已满，则会出现恐慌
	v.Uses++
}

// ReplaceControl在提供的索引处交换现有控件值
// 对于新值。索引必须引用有效的控件值。
func (b *Block) ReplaceControl(i int, v *Value) {
	b.Controls[i].Uses--
	b.Controls[i] = v
	v.Uses++
}

// CopyControls将此块的控件替换为
// 提供的块。未修改提供的块。
func (b *Block) CopyControls(from *Block) {
	if b == from {
		return
	}
	b.ResetControls()
	for _, c := range from.ControlValues() {
		b.AddControl(c)
	}
}

// 重置将块设置为提供的类型，并清除所有控制块
// 和辅助值。区块的其他属性，例如其继承者，
// 前置项和值保持不变。
func (b *Block) Reset(kind BlockKind) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
}

// resetWithControl重置b并添加控制v。
// 相当于b.Reset（种类）；b、 添加控制（v），
// 除了它是一个调用而不是两个调用，并且避免了边界检查。
// 它旨在供重写规则使用，如果这很重要的话。
func (b *Block) resetWithControl(kind BlockKind, v *Value) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
	b.Controls[0] = v
	v.Uses++
}

// resetWithControl2重置b并添加控件v和w。
// 相当于b.Reset（种类）；b、 AddControl（v）；b、 地址控制（w），
// 除了它是一个调用而不是三个调用，并且避免了两个边界检查。
// 它旨在供重写规则使用，如果这很重要的话。
func (b *Block) resetWithControl2(kind BlockKind, v, w *Value) {
	b.Kind = kind
	b.ResetControls()
	b.Aux = nil
	b.AuxInt = 0
	b.Controls[0] = v
	b.Controls[1] = w
	v.Uses++
	w.Uses++
}

// TRUNCTEVALUES截断第i个元素的b值，将后续元素归零。
// b中的值。我必须已经重置了参数之后的值，
// 要保持正确的值，请使用计数。
func (b *Block) truncateValues(i int) {
	tail := b.Values[i:]
	for j := range tail {
		tail[j] = nil
	}
	b.Values = b.Values[:i]
}

// AddEdgeTo将块b的边添加到块c。在建筑过程中使用
// SSA图；不要在已完成的SSA图上使用。
func (b *Block) AddEdgeTo(c *Block) {
	i := len(b.Succs)
	j := len(c.Preds)
	b.Succs = append(b.Succs, Edge{c, j})
	c.Preds = append(c.Preds, Edge{b, i})
	b.Func.invalidateCFG()
}

// removePred从b中删除第i条输入边。
// 调用者有责任删除
// 对应的后继边。
func (b *Block) removePred(i int) {
	n := len(b.Preds) - 1
	if i != n {
		e := b.Preds[n]
		b.Preds[i] = e
		// 更新我们移动的边的另一端。
		e.b.Succs[e.i].i = i
	}
	b.Preds[n] = Edge{}
	b.Preds = b.Preds[:n]
	b.Func.invalidateCFG()
}

// removeSucc从b中删除第i条输出边。
// 调用者有责任删除
// 对应的前置边。
func (b *Block) removeSucc(i int) {
	n := len(b.Succs) - 1
	if i != n {
		e := b.Succs[n]
		b.Succs[i] = e
		// 更新我们移动的边的另一端。
		e.b.Preds[e.i].i = i
	}
	b.Succs[n] = Edge{}
	b.Succs = b.Succs[:n]
	b.Func.invalidateCFG()
}

func (b *Block) swapSuccessors() {
	if len(b.Succs) != 2 {
		b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
	}
	e0 := b.Succs[0]
	e1 := b.Succs[1]
	b.Succs[0] = e1
	b.Succs[1] = e0
	e0.b.Preds[e0.i].i = 1
	e1.b.Preds[e1.i].i = 0
	b.Likely *= -1
}

// LackingPos指示b是否为应继承其位置的块
// 从它的继任者那里。如果其中的所有值都有不可靠的位置，则为真
// 如果它是“普通的”，这意味着没有控制流，这也是非常可能的
// 对应于一个很好理解的震源位置。
func (b *Block) LackingPos() bool {
	// 非普通前置是If或Defer，两者（1）都有两个后继，
	// 其中可能有不同的行号，（2）对应于语句
	// 在有位置的源代码中，所以无论如何都不应该发生这种情况。
	if b.Kind != BlockPlain {
		return false
	}
	if b.Pos != src.NoXPos {
		return false
	}
	for _, v := range b.Values {
		if v.LackingPos() {
			continue
		}
		return false
	}
	return true
}

func (b *Block) AuxIntString() string {
	switch b.Kind.AuxIntType() {
	case "int8":
		return fmt.Sprintf("%v", int8(b.AuxInt))
	case "uint8":
		return fmt.Sprintf("%v", uint8(b.AuxInt))
	default: // 指定了类型但未实现-打印为int64
		return fmt.Sprintf("%v", b.AuxInt)
	case "": // 无辅助int类型
		return ""
	}
}

// likelyBranch报告b区是否可能是其所有前身的分支。
func (b *Block) likelyBranch() bool {
	if len(b.Preds) == 0 {
		return false
	}
	for _, e := range b.Preds {
		p := e.b
		if len(p.Succs) == 1 || len(p.Succs) == 2 && (p.Likely == BranchLikely && p.Succs[0].b == b ||
			p.Likely == BranchUnlikely && p.Succs[1].b == b) {
			continue
		}
		return false
	}
	return true
}

func (b *Block) Logf(msg string, args ...interface{})   { b.Func.Logf(msg, args...) }
func (b *Block) Log() bool                              { return b.Func.Log() }
func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }

type BranchPrediction int8

const (
	BranchUnlikely = BranchPrediction(-1)
	BranchUnknown  = BranchPrediction(0)
	BranchLikely   = BranchPrediction(+1)
)
